
package com.gpstracking.BL;


import java.util.Date;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.gpstracking.BE.Area;
import com.gpstracking.BE.Condicion;
import com.gpstracking.BE.CondicionArea;
import com.gpstracking.BE.CondicionFechaHora;
import com.gpstracking.BE.CondicionInmovilidad;
import com.gpstracking.BE.DispositivoPosicion;
import com.gpstracking.BE.Notificacion;
import com.gpstracking.BE.NotificacionCondicion;
import com.gpstracking.DA.AreaDA;
import com.gpstracking.DA.CondicionDA;
import com.gpstracking.DA.CondicionFechaHoraDA;
import com.gpstracking.DA.DispositivoDA;
import com.gpstracking.DA.HUtil;
import com.gpstracking.DA.NotificacionDA;
import com.gpstracking.Utils.DateUtil;
import com.gpstracking.Utils.Geometry.Algorithms;
import com.gpstracking.Utils.Geometry.Polygon;


/**
 *
 * @author jmj
 */
public class Validador {
    
    Notificador notificador = new Notificador();
    DateUtil dateUtil = new DateUtil();
    Algorithms geometry = new Algorithms();
    public void validaDispoisitivo( DispositivoPosicion dispositivoPosicion ){
        checkAllNotification(DispositivoDA.getNotificaciones(dispositivoPosicion), dispositivoPosicion);
    }
    
    private void checkAllNotification( List<Notificacion> notificaciones , DispositivoPosicion dispositivoPosicion ){
        Date now = new Date();
        for( Notificacion it : notificaciones ){
            ThreadNotification tnot = new ThreadNotification( it, dispositivoPosicion, now );
            System.out.println("before start checkOneNotification");
            tnot.start();
        }
    }
    
    private class ThreadNotification extends Thread{
        Notificacion notificacion ;
        DispositivoPosicion dispositivoPosicion;
        Date fecha;
        public ThreadNotification(Notificacion notificacion, DispositivoPosicion dispositivoPosicion, Date fecha){
            this.notificacion = notificacion;
            this.dispositivoPosicion = dispositivoPosicion;
            this.fecha = fecha;
        }
        @Override
        public void run(){
        	System.out.println("checkOneNotification");
            checkOneNotification( notificacion , dispositivoPosicion, fecha);
        }
    }
    
    private void checkOneNotification( Notificacion notificacion, DispositivoPosicion dispositivoPosicion, Date fecha ){
        List< NotificacionCondicion > condiciones = NotificacionDA.getCondiciones( notificacion );
        System.out.println(condiciones.size());
        checkAllConditions( condiciones, notificacion , dispositivoPosicion, fecha );
    }
    private void checkAllConditions( List<NotificacionCondicion> condiciones , Notificacion notificacion, DispositivoPosicion dispositivoPosicion, Date fecha ){
        for( NotificacionCondicion it : condiciones ){
            ThreadCondition tcond = new ThreadCondition( it.getCondicion(), dispositivoPosicion, fecha, notificacion );
            System.out.println("before start checkOneCondition");
            tcond.start();
        }
    }
    private class ThreadCondition extends Thread{
        Condicion condicion ;
        DispositivoPosicion dispositivoPosicion;
        Date fecha;
        Notificacion notificacion;
        public ThreadCondition( Condicion condicion,DispositivoPosicion dispositivoPosicion, Date fecha, Notificacion notificacion ){
            this.condicion = condicion;
            this.dispositivoPosicion = dispositivoPosicion;
            this.fecha = fecha;
            this.notificacion = notificacion;
        }
        @Override
        public void run(){
        	System.out.println("checkOneCondition");
            checkOneCondition( condicion, dispositivoPosicion, fecha, notificacion );
        }
    }
    
    private void checkOneCondition( Condicion condition, DispositivoPosicion dispositivoPosicion, Date fecha, Notificacion notificacion ){
        List<CondicionArea> condicionesArea = CondicionDA.getCondicionAreas( condition);
        List<CondicionInmovilidad> condicionesInmo = CondicionDA.getCondicionInmovilidades( condition );
        
        if ( !condicionesArea.isEmpty() ){
            for( CondicionArea condicionArea : condicionesArea ){

                Area area = condicionArea.getArea();
                boolean typeArea = condicionArea.getDentroFuera().equals("Dentro") ? true :false;
                Polygon poly = AreaDA.getPoly( area );
                boolean debeNotificar = geometry.inPoly( DispositivoDA.getPoint(dispositivoPosicion) , poly ) != typeArea;
                
                List<CondicionFechaHora> condicionesFechaHora = CondicionFechaHoraDA.getCondicionesFechaHora( condicionArea );
                for( CondicionFechaHora condicionFechaHora : condicionesFechaHora ){
                
                    int type = 0;
                    if (condicionFechaHora.getRepite().equals( "actual" )) type = 0;
                    if (condicionFechaHora.getRepite().equals( "mensual" )) type = 30;
                    if (condicionFechaHora.getRepite().equals( "semanal" )) type = 7;
                    
                    if (dateUtil.inside(fecha, condicionFechaHora.getFechaInicio(), condicionFechaHora.getFechaFin(), dateUtil.getOffset( condicionFechaHora.getFechaInicio(), type) )){
                        if ( debeNotificar ) {
                            notificador.notificar(notificacion, condition, dispositivoPosicion.getDispositivo());
                        }
                    }
                }
                if ( condicionesFechaHora.isEmpty() && debeNotificar ){
                    notificador.notificar(notificacion, condition, dispositivoPosicion.getDispositivo());
                }
            }
        }
        
        if ( !condicionesInmo.isEmpty() ){
            for( CondicionInmovilidad condicionInmo : condicionesInmo ){
                List<CondicionFechaHora> condicionesFechaHora = CondicionFechaHoraDA.getCondicionesFechaHora( condicionInmo);
                for( CondicionFechaHora condicionFechaHora : condicionesFechaHora ){
                
                    int type = 0;
                    if (condicionFechaHora.getRepite().equals( "mensual" )) type = 30;
                    if (condicionFechaHora.getRepite().equals( "semanal" )) type = 7;
                    if (!dateUtil.inside(fecha, condicionFechaHora.getFechaInicio(), condicionFechaHora.getFechaFin(), dateUtil.getOffset( condicionFechaHora.getFechaInicio(), type) )){
                        notificador.notificar(notificacion, condition, dispositivoPosicion.getDispositivo());
                    }
                } 
                if (condicionesFechaHora.isEmpty() ){
                    //FIX:
                    // por definir reglas de "inmovilidad"
                    // distancia esferica
                }
            }
        }
        
    }
    
    public static void main(String [] args){
    	Session hbsession = HUtil.getSession();
    	Transaction tx = hbsession.beginTransaction();
    	tx.begin();
    	List<DispositivoPosicion> posiciones = hbsession.createQuery("FROM DispositivoPosicion").list();
    	
    
    	
    	for( DispositivoPosicion it : posiciones ){
    		new Validador().validaDispoisitivo(it);
    	
    	}
    }
}
